package com.yonyou.crm.sys.dataright.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.yonyou.crm.common.biz.service.BaseBizServiceImpl;
import com.yonyou.crm.common.exception.CrmMessageException;
import com.yonyou.crm.common.login.context.LoginContextConstant;
import com.yonyou.crm.common.model.util.IConverter;
import com.yonyou.crm.common.model.util.ModelUtil;
import com.yonyou.crm.sys.dataright.entity.RightConfig;
import com.yonyou.crm.sys.dataright.entity.RightTypeDO;
import com.yonyou.crm.sys.dataright.entity.RightTypeEnum;
import com.yonyou.crm.sys.dataright.entity.RightTypeVO;
import com.yonyou.crm.sys.dataright.entity.SuperVO;
import com.yonyou.crm.sys.dataright.handler.DeptHandler;
import com.yonyou.crm.sys.dataright.handler.MultiDeptHandler;
import com.yonyou.crm.sys.dataright.handler.MultiOrgHandler;
import com.yonyou.crm.sys.dataright.handler.OrgHandler;
import com.yonyou.crm.sys.dataright.handler.OwnerHandler;
import com.yonyou.crm.sys.dataright.handler.ParticipantHandler;
import com.yonyou.crm.sys.dataright.handler.RightHandler;
import com.yonyou.crm.sys.dataright.handler.TenantHandler;
import com.yonyou.crm.sys.org.entity.SysOrgTypeEnum;
import com.yonyou.crm.sys.org.entity.SysOrgVO;
import com.yonyou.crm.sys.org.service.SysOrgBizServiceImpl;
import com.yonyou.crm.sys.user.entity.UserVO;
import com.yonyou.crm.sys.user.service.UserBizServiceImpl;
import com.yonyou.crm.util.QueryUtils;
import com.yonyou.iuap.context.InvocationInfoProxy;

@Service
public class RightServiceImpl extends BaseBizServiceImpl<RightConfig> {
	
	@Autowired
	UserBizServiceImpl userService;
	@Autowired
	SysOrgBizServiceImpl sysOrgServoce;
	
	public String getRightSql(Long roleId, Long objId, Long actionId) {
		UserVO user = getCurUser();
		RightConfig config = getRightConfig(roleId, objId, actionId);
		if(config != null){
			int typeId = (int)config.getTypeId().longValue();
			RightHandler handler = getRightHandler(typeId,config,user);
			ParticipantHandler participantHandler = new ParticipantHandler(config,user.getId());
			return orSql(handler.getRightSql(),participantHandler.getRightSql());
		}
		return "1 != 1 ";
	}

	
	public boolean hasRight(Long roleId, Long objId, Long actionId, Long id) {
		UserVO user = getCurUser();
		RightConfig config = getRightConfig(roleId, objId, actionId);
		int typeId = (int)config.getTypeId().longValue();
		RightHandler handler = getRightHandler(typeId,config,user);
		ParticipantHandler participantHandler = new ParticipantHandler(config,user.getId());
		String tableName = config.getRightObject().getTableName();
		String where = orSql(handler.getRightSql(),participantHandler.getRightSql());
		String idPart = config.getRightObject().getPkField() + " = " + id;
		String wherePart = where + " and " + idPart;
		Map<String,String> paramMap = new HashMap<String,String>();
		paramMap.put("tableName", tableName);
		paramMap.put("wherePart", wherePart);
		Integer result = (Integer) dao.selectOne(RightConfig.class, "hasRight",paramMap);
		return result != null;
	}

	
	public boolean hasRight(Long roleId, Long objId, Long actionId, SuperVO vo) {
		UserVO user = getCurUser();
		RightConfig config = getRightConfig(roleId, objId, actionId);
		int typeId = (int)config.getTypeId().longValue();
		RightHandler handler = getRightHandler(typeId,config,user);
		ParticipantHandler participantHandler = new ParticipantHandler(config,user.getId());
		return handler.hasRight(vo) || participantHandler.hasRight(vo);
	}

	
	public Long[] filterWithRight(Long roleId, Long objId, Long actionId,
			Long[] ids) {
		UserVO user = getCurUser();
		RightConfig config = getRightConfig(roleId, objId, actionId);
		int typeId = (int)config.getTypeId().longValue();
		RightHandler handler = getRightHandler(typeId,config,user);
		ParticipantHandler participantHandler = new ParticipantHandler(config,user.getId());
		String tableName = config.getRightObject().getTableName();
		String where = orSql(handler.getRightSql(),participantHandler.getRightSql());
		QueryUtils idPart = new QueryUtils();
		idPart.append(config.getRightObject().getPkField(),ids);
		String wherePart = where + " and " + idPart;
		Map<String,String> paramMap = new HashMap<String,String>();
		paramMap.put("idField", config.getRightObject().getPkField());
		paramMap.put("tableName", tableName);
		paramMap.put("wherePart", wherePart);
		List<String> result = dao.selectStrList(RightConfig.class, "filterWithRight",paramMap);
		List<Long> resultLong = new ArrayList<Long>(result.size());
		for(int i=0,len=result.size();i<len;i++) {
			resultLong.add(Long.parseLong(result.get(i)));
		}
		return resultLong.toArray(new Long[0]);
	}

	
	public SuperVO[] filterWithRight(Long roleId, Long objId, Long actionId,
			SuperVO[] vos) {
		UserVO user = getCurUser();
		RightConfig config = getRightConfig(roleId, objId, actionId);
		int typeId = (int)config.getTypeId().longValue();
		RightHandler handler = getRightHandler(typeId,config,user);
		ParticipantHandler participantHandler = new ParticipantHandler(config,user.getId());
		return participantHandler.filterWithRight(handler.filterWithRight(vos));
	}

	
	public RightConfig getRightConfig(Long roleId, Long objId, Long actionId) {
		Map<String, Object> paraMap = new HashMap<String, Object>();
		paraMap.put("roleId", roleId);
		paraMap.put("objId", objId);
		paraMap.put("actionId", actionId);
		RightConfig config = (RightConfig) dao.selectOne(RightConfig.class, "getRightConfig", paraMap);
		return config;
	}
	private UserVO getCurUser() {
		//当前登陆人
		Long curUser = Long.parseLong(InvocationInfoProxy.getParameter(LoginContextConstant.UserId));
		UserVO user = userService.getDetail(curUser);
		return user;
	}
	private RightHandler getRightHandler(int typeId,RightConfig config,UserVO user) {
		RightHandler handler = new OwnerHandler(null,user.getId());
		if (RightTypeEnum.OWNER.getValue() == typeId) {
			handler = new OwnerHandler(config.getRightObject(),user.getId());
		} else if (RightTypeEnum.SELFDEPT.getValue() == typeId) {
			handler = new DeptHandler(config.getRightObject(),user.getDeptId());
		} else if (RightTypeEnum.SELFDEPTANDCHILD.getValue() == typeId) {
			Long deptId  = user.getDeptId();
			List<Long> ids = getMultiDeptIds(deptId,RightTypeEnum.SELFDEPTANDCHILD.getValue());
			handler = new MultiDeptHandler(config.getRightObject(),ids);
		} else if (RightTypeEnum.SELFORG.getValue() == typeId) {
			handler = new OrgHandler(config.getRightObject(),user.getOrgId());
		} else if (RightTypeEnum.SELFORGANDCHILD.getValue() == typeId) {
			Long orgId = user.getOrgId();
			List<Long> ids = getMultiDeptIds(orgId,RightTypeEnum.SELFORGANDCHILD.getValue());
			handler = new MultiOrgHandler(config.getRightObject(),ids);
		} else if (RightTypeEnum.TENANT.getValue() == typeId) {
			handler = new TenantHandler(config.getRightObject(),user.getTenantId());
		}
		return handler;
	}
	
	private List<Long> getMultiDeptIds(Long id,int type) {
		Map<String, Object> map = new HashMap<>();
		map.put("orgId", id);
		map.put("orgType", type);
 		List<String> subIdsByOrgId = sysOrgServoce.getIdsByCondition(map);
		List<Long> ids  = new ArrayList<Long>();
		for(String str : subIdsByOrgId){
			ids.add(Long.valueOf(str));
		}
		ids.add(id);
		return ids;
	}


	private String orSql(String... sqls) {
		return "(" + StringUtils.join(sqls," or ") + ")";
	}


	public void assign(Long roleId,String typeId) {
		List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
		String tenantId = InvocationInfoProxy.getTenantid();
		List<String> actions = dao.selectStrList(RightConfig.class,"getRightAction","");
		List<String> objects = dao.selectStrList(RightConfig.class,"getRightObject","");
		
		for(String action : actions){
			for(String object : objects){
				Map<String,Object> paramMap = new HashMap<>();
				paramMap.put("roleId", roleId);
				paramMap.put("tenantId", tenantId);
				paramMap.put("typeId", typeId);
				paramMap.put("actionId", action);
				paramMap.put("objId", object);
				list.add(paramMap);
			}
		}
		dao.deleteSql(RightConfig.class,"deleteRight",roleId);
		dao.saveSql(RightConfig.class,"insertRight",list);
			
	}


	public List<RightTypeVO> right(Long roleId) {
		Map<String,Object> paraMap = new HashMap<>();
		paraMap.put("roleId",roleId);
		List<RightTypeDO> selectList = dao.selectVoList(RightConfig.class, "right","");
		final String rightConfigDO = (String) dao.selectOne(RightConfig.class, "rightConfig",paraMap);
		List<RightTypeVO> rightTypeVOs = ModelUtil.copyModelList(selectList, RightTypeVO.class, new IConverter<RightTypeDO, RightTypeVO>() {
			@Override
			public void convert(RightTypeDO origObj, RightTypeVO destObj) {
				destObj.setChecked("F");
				if(origObj.getId().equals(rightConfigDO)){
					destObj.setChecked("T");
				}
			}
		});
		return rightTypeVOs;
	}
}
